最近比較沒空寫像樣的文章,不過還是來陪陪榜吧。
前一陣子在回文時,建議不要使用document.write(),但是沒有仔細去看看到底使用document.write會發生什麼事情,總覺得不太好。所以還是花一點時間測試看看,也檢視一下相關文件,看看今日的document.write()到底是怎樣執行的。
document.write()到底怎樣運作,其實跟瀏覽器怎麼做剖析,建立DOM的過程息息相關。本來這部份是各個瀏覽器自己要實作的,不過HTML5出來以後,有制定標準的方法:8.2 Parsing HTML documents,這裡面有一張圖,可以說明這個過程:
簡單地說,在剖析過程中,如果碰到script節點,執行時可能會產生新的文件內容,這時候就會剖析動態產生的文件內容,然後把它加入到DOM中。
例如:
<script>
var str = "<div>ok i'm a text node within div.</div>";
genode(str);
function genode(str) {
document.write(str);
}
</script>
執行完畢,就會在script node之後加入一個div:
這樣看起來還算順利,具體的說,用document.write產生的nodes,就會直接加在執行他的script node之後,也就是script node的nextSibling。另外,在執行script的時候,在他之前的node都已經加入到DOM,所以也可以透過script來存取:
<div id="panel"></div>
<script>
var str = "我踏月色而來";
genode(str, 'panel');
function genode(str, id) {
document.getElementById(id).innerHTML = str;
}
</script>
執行結果:
用起來很簡單吧。但是如果要使用document.write產生script,就會碰到奇怪的問題...例如:
<script>
var str = "<script type='text/javascript'>function foo(){alert('im changed XD')};</script>";
gencode(str);
function gencode(str) {
document.write(str);
}
function foo() {
alert('im a foo.');
}
</script>
<script>
foo();
</script>
執行起來卻會變成:
如果不加上script tag,就不會有script node加到DOM,也不會執行,但是加入script tag後,瀏覽器剖析的結果卻會是這樣(最新版的Chrome, Firefox, IE都一樣),不過其實有簡單的解法,就是在script tag內加上html區塊註解:
<script>
//<!--
var str = "<script type='text/javascript'>function foo(){alert('im changed XD')};</script>";
gencode(str);
function gencode(str) {
document.write(str);
}
function foo() {
alert('im a foo.');
}
//-->
</script>
這樣程式就可以跑了,當然還是在另外一個script node。
簡單的結論:
* document.write()無法在script node中嵌套script node
* document.write()所有執行的結果都會插入目前執行的script node之後
* 可以用html comment來避免javascript字串中有</script>被瀏覽器剖析的問題
泰大,您的5000...
cdfu提到:
泰大,您的5000...
再來啊,費大!! 不要說5000,再多都值!!
fillano提到:
可以用html comment來避免javascript字串中有</script>被瀏覽器剖析的問題
很實用
找了一下HTML 4.01,18.2.4 Dynamic modification of documents 裡面提到的行為,跟HTML5定義的已經不一樣了。就HTML 4.01的定義,呼叫document.write會用產生的文件內容取代script元素...所以一執行很多東西就不確定會怎樣
另外,使用html comment來避免瀏覽器剖析javascript程式中的東西,是HTML4.01就提到的:18.3.2 Hiding script data from user agents
我自己不建議用 document.write 的理由倒不是這個。
document.write 最可怕的是在 page ready 之後去用,他會把整個 body 裡面的東西改寫,
Ready 之前我倒是覺得還好,以前也常用,沒有太大問題。
現在的問題是在現在 ajax 當道的環境裡面,萬一不小心跑到 document.write 就完蛋了。
像這個case 如果有document.write
http://jsfiddle.net/Nk3N9/1/
沒有的時候
http://jsfiddle.net/Nk3N9/2/
千萬不能在畫面已經 render 完成之後去 call document.write ,
除非你真的是想要重新寫一個完整的頁面。
至於 "<script" 的問題,可以用 "<"+"script" 來躲就沒問了。
感謝補充,document.write是個大殺手阿
試跑了一下:
<pre class="c" name="code">
<script>
function gencode() {
document.write("<script>alert('oh no.')<"+"/script>all crashed.");
}
</script>
<div>I lived here.</div>
<input type="button" value="test" onclick="gencode()">
執行:
點一下按鈕:
結果就全毀:
這樣就更清楚document.write()的妙用了
我是用此方式就可以跑了
<pre class="c" name="code">
<script language="javascript">
var str = '<script type="text/javascript">window.alert("test");<\/script>';
document.write(str);
</script>
這個方法不錯,感謝。